package com.lagou.edu;

import com.lagou.edu.classloader.MyClassLoader;
import com.lagou.edu.pojo.Context;
import com.lagou.edu.pojo.Host;
import com.lagou.edu.pojo.Wrapper;
import com.lagou.edu.processor.RequestProcessor;
import com.lagou.edu.servlet.HttpServlet;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @ClassName: Bootstrap
 * @Auther: Jerry
 * @Date: 2020/7/30 22:44
 * @Desctiption: Minicat启动类
 * @Version: 1.0
 */
public class Bootstrap {

    /**Minicat服务器端口号*/
    private int port;

    private Host host;

    private Map<String, HttpServlet> httpServletMap = new ConcurrentHashMap<>();

    public void init() throws Exception {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("conf/server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            // 将输入流读取为文档进行解析
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            // 读取节点为servlet的信息
            List<Element> list = rootElement.selectNodes("//Service");
            for (int i = 0; i < list.size(); i++) {
                Element element = list.get(i);
                Element connectorEle = (Element) element.selectSingleNode("/Server/Service/Connector");
                String port = connectorEle.attributeValue("port");
                this.port = Integer.parseInt(port);

                Element hostEle = (Element) element.selectSingleNode("/Server/Service/Engine/Host");
                String name = hostEle.attributeValue("name");
                String appBase = hostEle.attributeValue("appBase");

                host = new Host(name, appBase);

                List<Context> contexts = host.getContextList();
                //获取webapps下所有目录
                File baseFile = new File(appBase);
                File[] files = baseFile.listFiles();
                for (File file : files) {
                    if (file.isDirectory()){
                        Context context = resolveContext(file.getAbsolutePath());
                        contexts.add(context);
                    }
                }
                host.setContextList(contexts);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    public Context resolveContext(String filePath) throws FileNotFoundException {
        Context context = new Context();
        context.setPath(filePath);
        String[] split = filePath.split("\\\\");
        String contextName = split[split.length - 1];
        context.setContextName(contextName);

        resolveServlet(context, filePath);

        return context;
    }

    private void resolveServlet(Context context,String filePath) throws FileNotFoundException {
        // 将配置文件读取为输入流
        InputStream resourceAsStream = new FileInputStream(filePath + File.separator + "web.xml");
        SAXReader saxReader = new SAXReader();
        try {
            // 将输入流读取为文档进行解析
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            // 读取节点为servlet的信息
            List<Element> list = rootElement.selectNodes("//servlet");
            for (int i = 0; i < list.size(); i++) {
                Element element = list.get(i);

                // 读取servlet-name节点的值
                String servletName = element.selectSingleNode("servlet-name").getStringValue();
                // 读取servlet-class节点的值
                String servletClass = element.selectSingleNode("servlet-class").getStringValue();

                MyClassLoader classLoader = new MyClassLoader(filePath + File.separator + "server");
                Class<?> clazz = classLoader.loadClass(servletClass);

                Element servletMapping = (Element) element.selectSingleNode("/web-app/servlet-mapping[servlet-name= '" + servletName + "']");

                // 读取url-pattern节点的值
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

                Wrapper wrapper = new Wrapper();
                wrapper.setPath(urlPattern);
                wrapper.setServlet((HttpServlet) clazz.newInstance());
                context.addWrapper(wrapper);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**Minicat初始化*/
    public void start() throws Exception {
        // 加载并解析web.xml文件
//        loadConfig();

        // 创建一个线程池
        ThreadPoolExecutor executor = createExecutor();


        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("=====>>> start on port:" + port);

        /**Minicat V1.0版本*/
        /*while (true) {
            Socket socket = serverSocket.accept();
            String content = "Hello Minicat!";
            String responseText = HttpProtocolUtil.getHeader200(content.getBytes().length) + content;
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(responseText.getBytes());
            socket.close();
        }*/

        /**Minicat V2.0版本*/
        /*while (true) {
            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream inputStream = socket.getInputStream();
            // 构建Request信息
            Request request = new Request(inputStream);

            // 构建Response信息
            Response response = new Response(socket.getOutputStream());
            response.outputHtml(request.getUri());
            socket.close();
        }*/

        /**Minicat V3.0版本*/
        /*while (true) {
            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream inputStream = socket.getInputStream();
            // 构建Request信息
            Request request = new Request(inputStream);

            // 构建Response信息
            Response response = new Response(socket.getOutputStream());

            if (httpServletMap.get(request.getUri()) == null) {
                response.outputHtml(request.getUri());
            } else {
                HttpServlet httpServlet = httpServletMap.get(request.getUri());
                httpServlet.service(request, response);
            }
            socket.close();
        }*/

        /*while (true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, httpServletMap);
            // 多线程改造
            requestProcessor.start();
        }*/

        while (true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, host);

            // 线程池改造
            executor.execute(requestProcessor);
        }
    }

    private ThreadPoolExecutor createExecutor() {
        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * 加载并解析web.xml配置文件
     */
    /*private void loadConfig() {
        // 将配置文件读取为输入流
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();
        try {
            // 将输入流读取为文档进行解析
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            // 读取节点为servlet的信息
            List<Element> list = rootElement.selectNodes("//servlet");
            for (int i = 0; i < list.size(); i++) {
                Element element = list.get(i);

                // 读取servlet-name节点的值
                String servletName = element.selectSingleNode("servlet-name").getStringValue();
                // 读取servlet-class节点的值
                String servletClass = element.selectSingleNode("servlet-class").getStringValue();

                Element servletMapping = (Element) element.selectSingleNode("/web-app/servlet-mapping[servlet-name= '" + servletName + "']");

                // 读取url-pattern节点的值
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();

                // 获取Servlet实例
                Object obj = Class.forName(servletClass).newInstance();

                httpServletMap.put(urlPattern, (HttpServlet) obj);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }*/

    public static void main(String[] args) throws Exception {
        Bootstrap bootstrap = new Bootstrap();
        // 初始化服务
        bootstrap.init();
        // 启动服务
        bootstrap.start();
    }
}
